import { useCallback, useState } from "react";
import { v4 as uuid } from "uuid";
import { faPlus, faFileImport } from "@fortawesome/free-solid-svg-icons";
import SimpleMDE from "react-simplemde-editor";
import "easymde/dist/easymde.min.css";
import FileSearch from "@/components/file-search/FileSearch";
import FileList from "@/components/file-list/FileList";
import BottomBtn from "@/components/bottom-btn/BottomBtn";
import TabList from "@/components/tab-list/TabList";
import Loading from "@/components/loading/Loading";
import { useIpcRendererOn, useIpcRendererEmit } from "@/hooks/useIpcRenderer";
import fileHelper from "@/utils/helper";
import { objToArr, arrToObj } from "@/utils/tools";
import Types from "@/const/eventName";
import "./App.css";

// comonjs modules
const { join, dirname, basename } = window.require("path");
const { ipcRenderer } = window.require("electron");

function App() {
  const [storeFiles, setStoreFiles] = useState({});
  const [saveLocation, setSaveLocation] = useState("");
  const [activeFileId, setActiveFileId] = useState(null);
  const [openFiles, setOpenFiles] = useState([]);
  const [unsaveIds, setUnsaveIds] = useState([]);
  const [canSync, setCanSync] = useState(false); // 是否可以同步
  const [loading, setLoading] = useState(false); // loading
  const [filterName, setFilterName] = useState("");
  const files = objToArr(storeFiles).filter((f) => f.name.includes(filterName));
  const activeFile = files.find((f) => f.id === activeFileId);

  // 点击文件
  const handleFileClick = (file) => {
    if (!file.isLoaded) {
      fileHelper.readFile(file.path).then((val) => {
        setStoreFiles({
          ...storeFiles,
          [file.id]: { ...file, isLoaded: true, content: val },
        });
        setActiveFileId(file.id);
        if (!openFiles.some((f) => f.id === file.id)) {
          setOpenFiles([...openFiles, file]);
        }
      });
    } else {
      setActiveFileId(file.id);
      if (!openFiles.some((f) => f.id === file.id)) {
        setOpenFiles([...openFiles, file]);
      }
    }
  };
  const handleFileDel = (file) => {
    const { id } = file;
    fileHelper.deleteFile(file.path).then(() => {
      const { [id]: file, ...afterDele } = storeFiles;
      const newOpen = openFiles.filter((f) => f.id !== id);
      setOpenFiles(newOpen);
      if (activeFileId === id) {
        setActiveFileId(newOpen.length ? newOpen[0].id : null);
      }
      setStoreFiles(afterDele);
      ipcRenderer.send(Types.UPDATEFILESTOREFILES, {
        files: [file],
        isDelete: true,
      });
      if (canSync) {
        setLoading(true);
        ipcRenderer.send(Types.OSSDELETE, file);
      }
    });
  };
  const handleFileNameEdit = useCallback(
    (fileId, mofifyName) => {
      const { id, isLoaded, isNew, content, path } = storeFiles[fileId];
      const newName = mofifyName.replace(/(\.md)$/, "");
      const newPath = isNew
        ? join(saveLocation, `${newName}.md`)
        : join(dirname(path), `${newName}.md`);
      const newFile = { id, name: `${newName}.md`, path: newPath };
      if (isNew) {
        //新建文件,创建文件
        fileHelper.createFile(newPath, "").then(() => {
          const newStore = {
            ...storeFiles,
            [id]: { ...newFile, isLoaded, content },
          };
          setStoreFiles(newStore);
          ipcRenderer.send(Types.UPDATEFILESTOREFILES, { files: [newFile] });
        });
      } else {
        //修改文件名字
        fileHelper.renameFile(path, newPath).then(() => {
          setStoreFiles((prev) => ({
            ...prev,
            [id]: { ...newFile, isLoaded, content },
          }));
          setOpenFiles((p) => {
            const newP = p.map((f) => {
              if (f.id === id) {
                f.name = newName;
              }
              return f;
            });
            return newP;
          });
          ipcRenderer.send(Types.UPDATEFILESTOREFILES, { files: [newFile] });
        });
      }
    },
    [storeFiles, saveLocation]
  );
  const handleTabFileClose = (file) => {
    const newFiles = openFiles.filter((f) => f.id !== file.id);
    if (activeFileId === file.id) {
      setActiveFileId(newFiles.length ? newFiles[0].id : null);
    }
    setOpenFiles(newFiles);
  };
  const handleSearch = useCallback((text) => {
    setFilterName(text);
  }, []);

  // 编辑 修改
  const handleEditChange = (newCont) => {
    const { content } = activeFile;
    if (content === newCont) {
      return;
    }
    const newFile = { ...activeFile, content: newCont };
    setStoreFiles({ ...storeFiles, [activeFileId]: newFile });
    if (!unsaveIds.includes(activeFileId)) {
      setUnsaveIds([...unsaveIds, activeFileId]);
    }
  };

  // 保存
  const handleSave = () => {
    const { id, path, content } = activeFile;
    if (!unsaveIds.includes(id)) {
      //未修改
      return;
    }
    fileHelper.writeFile(path, content).then(() => {
      const arr = unsaveIds.filter((pid) => id !== pid);
      setUnsaveIds(arr);
      if (canSync) {
        setLoading(true);
        ipcRenderer.send(Types.OSSUPLOAD, path);
      }
    });
  };
  // 新建
  const createClick = () => {
    const id = uuid();
    const newFile = {
      id,
      name: "新建文档",
      path: join(saveLocation, "新建文档.md"),
      isNew: true,
    };
    setStoreFiles((storeFiles) => ({ ...storeFiles, [id]: newFile }));
  };

  // 导入
  const importClick = () => ipcRenderer.send(Types.OPENFILEDIALOG);

  const doImports = (filePaths = []) => {
    const alreadExists = objToArr(storeFiles);
    const filterFiles = filePaths
      .filter((p) => !alreadExists.some((f) => f.path === p))
      .map((p) => {
        return { id: uuid(), path: p, name: basename(p) };
      });
    const newStores = { ...storeFiles, ...arrToObj(filterFiles) };
    setStoreFiles(newStores);
    ipcRenderer.send(Types.UPDATEFILESTOREFILES, { files: filterFiles });
  };

  // 进程通讯
  const onEventMap = {
    [Types.OPENFILEDIALOGREPLY]: (_, { filePaths }) => doImports(filePaths),
    [Types.SAVEEDITFILE]: () => handleSave(),
    [Types.CREATENEWFILE]: () => createClick(),
    [Types.IMPORTFILE]: () => importClick(),
    [Types.GETDOCPATHREPLY]: (_, path) => setSaveLocation(path),
    [Types.GETFILESTOREFILESREPLY]: (_, files) => setStoreFiles(files),
    [Types.OSSSYNCINFOCHANGE]: (_, canSync) => setCanSync(canSync),
    [Types.GETOSSCONFIGREPLY]: (_, { enable }) => setCanSync(enable),
    [Types.OSSREPLY]: () => setLoading(false),
  };
  useIpcRendererOn(onEventMap);

  // 发送事件
  const emitEventList = [
    Types.GETDOCPATH,
    Types.GETFILESTOREFILES,
    Types.GETOSSCONFIG, // 是否可以同步初始化
  ];
  useIpcRendererEmit(emitEventList);

  return (
    <div className="App container-fluid mx-0 px-0">
      {loading && <Loading />}
      <div className="row no-gutters app-box">
        <div className="col-3 pannel-left">
          <FileSearch onFileSearch={handleSearch} />
          <FileList
            fileList={files}
            activeFileId={activeFileId}
            onFileDel={handleFileDel}
            onFileClick={handleFileClick}
            onFileNameEdit={handleFileNameEdit}
          />
          <div className="row no-gutters bottom-btns">
            <div className="col">
              <BottomBtn title="新建" icon={faPlus} itemClick={createClick} />
            </div>
            <div className="col">
              <BottomBtn
                title="导入"
                icon={faFileImport}
                cls="blue"
                itemClick={importClick}
              />
            </div>
          </div>
        </div>
        <div className="col-9 pannel-right">
          {activeFile ? (
            <>
              <TabList
                fileList={openFiles}
                activeId={activeFileId}
                unsaveIds={unsaveIds}
                onTabClick={(file) => setActiveFileId(file.id)}
                onTabClose={handleTabFileClose}
              />
              <SimpleMDE
                key={activeFile.id}
                onChange={handleEditChange}
                value={activeFile.content}
                options={{
                  lineNumbers: false,
                  minHeight: "460px",
                  maxHeight: "460px",
                }}
              />
            </>
          ) : (
            <div className="empty-tip">选择或创建 Markdown 文档</div>
          )}
        </div>
      </div>
    </div>
  );
}

export default App;
